﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace chudb
{
    using Engine;

    public class ChuSpace
    {
        internal string SName { get; set; }
        internal ChuEngine Engine { get; set; }
        internal BsonValue _NowId { get; set; }
        public ChuSpace(ChuEngine db, string space_name)
        {
            this.Engine = db;
            this.SName = space_name;
        }
        public BsonValue Id { get { return _NowId; } }
        public ChuSpace Goto(BsonValue id)
        {
            this._NowId = id;
            return this;
        }
        public int Delete(params BsonValue[] ids)
        {
            return Engine.Delete(SName, ids);
        }
        public ChuSpace DeleteNow()
        {
            if (!_NowId.IsNull)
            {
                Delete(_NowId);
                _NowId = BsonValue.Null;
            }
            return this;
        }
        public BsonValue Read(string name)
        {
            if (_NowId.IsNull) return BsonValue.Null;
            var item = Find(_NowId);
            if (item != null && item.ContainsKey(name)) return item[name];
            return BsonValue.Null;
        }
        public bool Store(string name, BsonValue value)
        {
            if (_NowId.IsNull) return false;
            var item = Find(_NowId);
            if (item == null) item = new BsonDocument { ["_id"] = _NowId, [name] = value };
            else
            {
                if (item.ContainsKey(name) && item[name] == value) return true;
                item[name] = value;
            }
            if (Engine.BeginTrans())
            {
                try
                {
                    Engine.Upsert(SName, [item], BsonAutoId.ObjectId);
                    Engine.Commit();
                    return true;
                }
                catch
                {
                    Engine.Rollback();
                }
            }
            return false;
        }
        public bool Remove(string name)
        {
            if (_NowId.IsNull) return false;
            var item = Find(_NowId);
            if (item == null || !item.ContainsKey(name)) return true;
            item.Remove(name);
            if (Engine.BeginTrans())
            {
                try
                {
                    Engine.Upsert(SName, [item], BsonAutoId.ObjectId);
                    Engine.Commit();
                    return true;
                }
                catch
                {
                    Engine.Rollback();
                }
            }
            return false;
        }
        public BsonDocument Find(BsonValue id)
        {
            var query = new Query();
            query.Where.Add(Query.EQ("_id", id));
            return Engine.Query(SName, query).FirstOrDefault()?.AsDocument;
        }
        public IEnumerable<BsonDocument> FindAll(params BsonExpression[] expressions)
        {
            var query = new Query();
            query.Where.AddRange(expressions);
            foreach (var bson in Engine.Query(SName, query).ToEnumerable()) yield return bson.AsDocument;
        }
        public IEnumerable<BsonDocument> FindAll(Query query)
        {
            foreach (var bson in Engine.Query(SName, query).ToEnumerable()) yield return bson.AsDocument;
        }
        public ChuQuery NewQuery()
        {
            return new ChuQuery(this);
        }
        //collection.EnsureIndex("Name", true, "LOWER($.Name)")
        public bool EnsureIndex(string name, string expression, bool unique = false)
        {
            return Engine.EnsureIndex(SName, name, BsonExpression.Create(expression), false);
        }
        public bool DropIndex(string name)
        {
            return Engine.DropIndex(SName, name);
        }
        public int Count{
            get
            {
                var query = new Query();
                query.Select = BsonExpression.Create("COUNT(*)");
                return Engine.Query(SName, query).FirstOrDefault()? .AsDocument["expr"] ?? 0;
            }
        }
    }
}
